package leeon.bbsbrower.util;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.crimson.tree.XmlDocument;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.w3c.dom.Text;
import org.xml.sax.SAXException;

public class XmlOperator {
		
	/**
	 * 从制定的file中读取xml.
	 * 如果file不存在,那么生成一个并且加上root节点
	 * @param file
	 * @return
	 */
	public static Document createXmlDocument(File file, String rootTag) {
		InputStream input = null;
		try {
			
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = factory.newDocumentBuilder();
			
			Document doc = null;
			if (file.exists()) {
				doc = docBuilder.parse(file);
			} else {
				doc = docBuilder.newDocument();
				Element root = doc.createElement(rootTag);
				doc.appendChild(root);
			}
			
			return doc;
			
		} catch (ParserConfigurationException e) {
			// TODO 自动生成 catch 块			
			e.printStackTrace();
		} catch (FileNotFoundException e) {
			// TODO 自动生成 catch 块			
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} finally {			
			try {
				if (input != null) input.close();
			} catch (IOException e) {
				// TODO 自动生成 catch 块
				e.printStackTrace();
			}
		}
		
		return null;
		
	}
	
	/**
	 * 清除一些回车或者换行的text节点
	 * @param node
	 * @param tab
	 */
	private static void clearNoUseTextNode(Node node) {
		NodeList nodes = node.getChildNodes();		
		for (int i = nodes.getLength() - 1; i >= 0 ; i --) {
			Node n = nodes.item(i);
			//找到没有意义的text node						
			if (n.getNodeType() == Node.TEXT_NODE && n.getNodeValue() != null && n.getNodeValue().trim().length() == 0) {
				node.removeChild(n);
			} else {
				//否则继续递归下面的节点				
				clearNoUseTextNode(n);
			}
		}		
	}
	
	/**
	 * 将更新过的doc写入xml中
	 * @param file
	 * @param doc
	 */
	public static void saveDocument(File file, Document doc) {
		
		try {
			clearNoUseTextNode(doc);
			
			FileOutputStream outStream = new FileOutputStream(file);
			OutputStreamWriter outWriter = new OutputStreamWriter(outStream, "UTF-8");
			((XmlDocument) doc).write(outWriter, "UTF-8");
			outWriter.close();
			outStream.close();

		} catch (FileNotFoundException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		}

	}
	
	/**
	 * 在element节点下，加一个名字为textNodeName的textnode, textvalue为text的值
	 * @param element
	 * @param textNodeName
	 * @param textNodeValue
	 */
	public static Element createTextNode(Document doc, String textNodeName, String textNodeValue) {
		Element element = doc.createElement(textNodeName);
		Text text = doc.createTextNode(textNodeValue);
		element.appendChild(text);
		return element;
	}
	
	/**
	 * 插入节点，节点始终是同名节点的第一个
	 * @param parent 需要插入的文档
	 * @param element 需要插入的节点
	 * @param order 定义插入节点到什么位置的数组，比如{"project", "app-server", "ejb"}
	 * @param append 是添加同组tag的最后一个还是放在第一个
	 */
	public static void insertElement(Element parent, Element element, String[] order, boolean append) {
		 
		//如果没有子节点，那么直接添加
		if (parent.getChildNodes().getLength() == 0) {
			parent.appendChild(element);
		} else {
			//查找和插入的节点同名的节点
			NodeList nodes = parent.getElementsByTagName(element.getTagName());
			//如果有同名节点
			if (nodes.getLength() != 0) {
				//如果是append,那么取最后一个节点append的下一个insert
				if (append) {
					Node node = nodes.item(nodes.getLength()-1).getNextSibling();
					//如果下一个节点不是空,那么insertBefort下一个节点,否则直接append到parent最后
					if (node != null) {
						parent.insertBefore(element, node);
					} else {
						parent.appendChild(element);
					}
				//如果是insertBefor的模式
				} else {
					parent.insertBefore(element, nodes.item(0));
				}
			
			//没有同名节点
			} else {
				//没有同名的,那么从order中找出存在的该Node后的Node中存在的最开始的一个,如果没有,直接append到parent中
				nodes = null;
				for (int i = order.length - 1; i >= 0; i--) {					
					//如果已经从后循环到加入的tag了,那么结束循环
					if (order[i].equals(element.getTagName())) {
						break;
					//找到了存在的靠后得node，赋值给nodes
					} else if (parent.getElementsByTagName(order[i]).getLength() != 0) {
						nodes = parent.getElementsByTagName(order[i]);
					} 					
				}
				
				//如果nodes == null,说明必须将element加入parent得最后一个
				//否则,加入到nodes0得前面
				if (nodes != null) {
					parent.insertBefore(element, nodes.item(0));
				} else {
					parent.appendChild(element);
				}
				
			}
		}
	}
	
	/**
	 * 读取函数,
	 * @param file
	 */
	public static Document readDocument(File file) {
		InputStream input = null;
		//解析xml
		try {
			DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
			DocumentBuilder docBuilder = factory.newDocumentBuilder();
			Document document = docBuilder.parse(file);
			return document;
			
		} catch (SAXException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (IOException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			// TODO 自动生成 catch 块
			e.printStackTrace();
		} finally {
			if (input != null) {
				try {
					input.close();
				} catch (IOException e) {
					// TODO 自动生成 catch 块
					e.printStackTrace();
				}
			}
		}
		return null;
	}
	
	/**
	 * 获取一个节点下的tagName节点的text值
	 * @param element
	 * @param tagName
	 * @return
	 */
	public static String getTextValueByTagName(Element element, String tagName) {
		List<String> list = getTextValuesByTagName(element, tagName);
		if (list.size() != 0)
			return list.get(0);
		else
			return null;
	}
	
	/**
	 * 获取一个节点下的 tagName节点的text值
	 * @param Element
	 * @return
	 */
	public static List<String> getTextValuesByTagName(Element element, String tagName) {
		NodeList nodeList = element.getElementsByTagName(tagName);
		ArrayList<String> list = new ArrayList<String>();
		for (int i = 0; i < nodeList.getLength(); i++) {
			list.add(getTextValue(nodeList.item(i)));
		}
		return list;
	}

	
	/**
	 * 获取一个node节点下的text的方法
	 * 如果有text返回text,没有text,有cdata,返回第一个cdata
	 * @param node
	 * @return
	 */
	public static String getTextValue(Node node) {
		String textValue = null;
		int length = node.getChildNodes().getLength();

		if (length > 0) {
			textValue = node.getChildNodes().item(0).getNodeValue();

			if (length > 1
					&& (textValue == null || textValue.trim().length() == 0)) {
				textValue = node.getChildNodes().item(1).getNodeValue();
			}

			if (textValue != null) {
				textValue = textValue.trim();
			}
		}
		return textValue;
	}
	
}
